Skip to content

Conversation

@ericli3690
Copy link
Member

@ericli3690 ericli3690 commented Aug 29, 2025

Blocked by dependency Currently blocked by some other dependent / related change :

Purpose / Description

Adds an advanced review reminder option. When this setting is enabled, the review reminder only triggers notifications if the deck the review reminder is for has not been reviewed yet today.

Adds a checkbox to the AddEditReminderDialog to toggle this setting on or off. Adds a method to NotificationService to check if a deck (or all decks) have been reviewed yet today. The check is accomplished via a database query of the revlog and cards tables. In my experience there is no noticeable latency, the query I've written should be fairly efficient.

UI

image

Fixes

  • GSoC 2025: Review Reminders

Approach

The SQL query is:

SELECT EXISTS (
    SELECT 1
    FROM cards
    JOIN revlog ON revlog.cid = cards.id
    WHERE revlog.id > $startOfToday
    AND cards.did = ${scope.did} -- this line is removed if the scope is Global
)

Where startOfToday is calculated via sched.dayCutoff - 1.days.inWholeSeconds.

How Has This Been Tested?

  • Unit tests pass.
  • Builds and runs on a physical Samsung S23, API 34.
  • Based on my own personal testing, it seems the feature works! I created a few review reminders, reviewed a few cards, etc.

Learning (optional, can help others)

I found the database schema wiki page useful: https://github.com/ankidroid/Anki-Android/wiki/Database-Structure

Checklist

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

@ericli3690 ericli3690 added Needs Review GSoC Pull requests authored by a Google Summer of Code participant [Candidate/Selected], for GSoC mentors Blocked by dependency Currently blocked by some other dependent / related change labels Aug 29, 2025
@ericli3690 ericli3690 force-pushed the ericli3690-review-reminders-only-notify-if-no-reviews branch from 9f44e2d to 787f50a Compare September 6, 2025 05:19
@ericli3690
Copy link
Member Author

  • Rebased.

@ericli3690 ericli3690 force-pushed the ericli3690-review-reminders-only-notify-if-no-reviews branch from 787f50a to f8c1584 Compare September 7, 2025 17:27
@ericli3690
Copy link
Member Author

  • Rebased.

GSoC 2025: Review Reminders

- `initializeScheduleRemindersDeckSpinner` doesn't properly handle what happens if showAllDecks is true. This makes pressing on a deck select the wrong deck. This commit fixes this.
GSoC 2025: Review Reminders

- Added TimePicker styling, used when users edit the time of a review reminder.
GSoC 2025: Review Reminders

- The AddEditReminderDialog displays the current time in the TimePicker when a review reminder is being created. This change adds a utility function to ReviewReminderTime's companion object to calculate this time. I decided to put this function within ReviewReminderTime so it can be accessed by both AddEditReminderDialog and AddEditReminderDialogViewModel.
GSoC 2025: Review Reminders

- XML file for AddEditReminderDialog. Allows time and deck modification. Also has a dropdown for advanced settings, including minimum card trigger threshold (with more advanced settings hopefully coming soon). The advanced settings will be grouped under a dropdown to prevent them from overwhelming users when the dialog initially opens.
GSoC 2025: Review Reminders

- Creates AddEditReminderDialog.
- Adds DialogMode, which represents whether the dialog is in adding or editing mode.
- Created a ViewModel for the AddEditReminderDialog. A specific view model is created because this allows the dialog's state to persist across redraws, ex. if the theme changes, if the device rotates, etc. It also centralizes the data of the review reminder being edited in a single source of truth.
- Sets submit, cancel, and delete actions for the dialog; this is the main way users can delete review reminders. Deletion is locked behind a confirmation box just in case the user accidentally clicks the button.
- Results for the deck picker dropdown in the dialog are received in ScheduleReminders and sent to the AddEditReminderDialog via a FragmentResult. See the docstring of `onDeckSelected` in ScheduleReminders to see why this is done.
- Filling in the values in the dialog fields and setting listeners for when the values change is pulled out into a separate methods for readability.
- Adds `showTimePickerDialog`. Shows a TimePicker dialog for picking review reminder time via modern Material3 guidelines. Overrides `onConfigurationChanged` to properly handle device rotation, which for some reason is not handled by default by MaterialTimePicker.
- An edited review reminder is passed back to ReviewRemindersDatabase as a FragmentResult, which is a simple way of passing information between fragments.
GSoC 2025: Review Reminders

- Adds a fragment result listener to ScheduleReminders to detect when an AddEditReminderDialog has completed, and if so, edits the database and UI accordingly.
- Filled out the `addReminder` and `editReminder` methods to show the AddEditReminderDialog.
GSoC 2025: Review Reminders

- Added logic for checking if a deck exists before returning deck-specific reminders to ReviewRemindersDatabase. This code uses the `decks.have` method, since it seemed like the most straightforward way to accomplish deck-existence-checking.
- `decks.have` was previously marked as "unused". I've removed this annotation.
- Added a deleteAllRemindersForDeck helper method. It's public because it will also be used in NotificationService.
- Had to mark a few database methods as suspending since they use the collection to check if a deck exists. This in turn meant wrapping some of the tests in the test file with `runTest` and marking the database access wrapper in ScheduleReminders with `suspend`. Also had to explicitly create decks using `addDeck` in the test file. Moved the dummy review reminder declarations to setUp to accommodate this.
- Added new tests for deck deletion functionality.
GSoC 2025: Review Reminders

- Added logic for review reminder notifications being sent to the user. Alarms for sending notifications are created by AlarmManagerService, and the actual notifications themselves are fired by NotificationService.
- Moved catchAlarmManagerExceptions method that was previously in BootService to AlarmManagerService to ensure no regressions occur and old bugs are still solved.
- `scheduleReviewReminderNotification` is the primary part of AlarmManagerService, setting the recurring notifications for a review reminder. `unschedule` and `scheduleAll` methods are also provided.
- Snoozing is handled by AlarmManagerService via `scheduleSnoozedNotification`. AlarmManagerService must be a BroadcastReceiver so that it can receive snoozing requests via onReceive from PendingIntents created by NotificationService.
- `sendReviewReminderNotification` in NotificationService does the bulk of the work for sending notifications, filling out content, etc.
- `fireReviewReminderNotification` is a separate method that handles the actual OS call to fire the notification itself.
- Marked old functionality in NotificationService as legacy notification code.
- Had to create a NotificationServiceAction sealed class to mark the kinds of notification requests the NotificationService gets. These different requests must have different actions set, otherwise they collide with each other and interfere. This can cause snoozes to cancel normal notifications, normal notifications to cancel snoozes, etc., hence why we add this sealed class.
- NotificationService must be a BroadcastReceiver because it needs to listen to PendingIntents triggered by AlarmManager alarms, which trigger the onReceive method.
- Added unit tests for AlarmManagerService and NotificationService.
- Added AlarmManagerService as a BroadcastReceiver to the AndroidManifest.xml file.
- Added calls to set review reminder notifications on device boot-up and app start-up to AnkiDroidApp and BootService.
- Renamed the inner field of ReviewReminderId to avoid confusing calls to `reviewReminder.id.id`.
…rs-dialog-august' into ericli3690-review-reminders-integrated-firing
GSoC 2025: Review Reminders

- Modifies ScheduleReminders so that it sets alarms for review reminders via AlarmManagerService.
GSoC 2025: Review Reminders

Adds an advanced review reminder option. When this setting is enabled, the review reminder only triggers notifications if the deck the review reminder is for has not been reviewed yet today.

Adds a checkbox to the AddEditReminderDialog to toggle this setting on or off. Adds a method to NotificationService to check if a deck (or all decks) have been reviewed yet today. The check is accomplished via a database query of the `revlog` and `cards` tables. In my experience there is no noticeable latency, the query I've written should be fairly efficient.

Adds a boolean field to store the state of this setting to ReviewReminder. Adds unit tests.
@ericli3690 ericli3690 force-pushed the ericli3690-review-reminders-only-notify-if-no-reviews branch from f8c1584 to 5b3ac81 Compare September 9, 2025 05:56
@ericli3690
Copy link
Member Author

  • Rebased.

@ericli3690 ericli3690 marked this pull request as draft September 26, 2025 04:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Blocked by dependency Currently blocked by some other dependent / related change GSoC Pull requests authored by a Google Summer of Code participant [Candidate/Selected], for GSoC mentors Has Conflicts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant